import breve, math

#constants
WORLD_SIZE = 40
SENSOR_DISTANCE = 10
PREY_DISTANCE_SENSE_TO_PREDATOR = 4
PREDATOR_DISTANCE_SENSE_TO_PREY = 15

FOOD_INIT_COUNT = 60
PREY_INIT_COUNT = 20
PREDATOR_INIT_COUNT = 9
MAX_PREY_COUNT = 50

MAX_FITNESS = 100

HUNGER_LEVEL_STEP = 0.1
HUNGER_LEVEL_TO_ACTIVATE_SENSE = 70

PREDATOR_HUNGER_LEVEL_TO_ACTIVATE_SENSE = 40

HUNGER_LEVEL_SENSE_PART = 0.2
REPRODUCTION_TIME = 20.0
PAUSE_AFTER_REPRODUCTION = 20.0

MAX_PREDATOR_REPRODUCTION = 7
MAX_PREY_REPRODUCTION = 3

ENERGY_LEVEL_STEP = 0.4

AGE_STEP = 3
FOOD_BURNING_STEP = 3

MIN_FOOD_LEVEL_FOR_REPRODUCTION = 30
MIN_AGE_FOR_REPRODUCTION = 20
MAX_AGE_FOR_REPRODUCTION = 80
AGE_SPEED_LEVEL = 50

PREY_SPEED = 1.0
PREY_MAX_SPEED = 1.5
PREY_MIN_SPEED = 0.2
PREDATOR_SPEED = 1.0
PREDATOR_MAX_SPEED = 1.5
PREDATOR_MIN_SPEED = 1.5

FITNESS_MEAN_INDEX = 0
FITNESS_FOOD_BURNING_SPEED_INDEX = 1
FITNESS_FOOD_EATING_SPEED_INDEX = 2
FITNESS_VELOCITY_INCREASE_SPEED_INDEX = 3
FITNESS_SENSE_DISTANCE_INDEX = 4
FITNESS_SIZE = 5

MIN_SPEED = 0.2
MAX_SPEED = 2.0

GRAPH_TIME_STEP = 2
GRAPH_STEPS_COUNT = 500
PARTS = 3

###################################################
##################### CONTROL #####################
###################################################
class MyControl(breve.Control):
	def __init__(self):
		breve.Control.__init__(self)
		self.disableReflections()
		self.surface = breve.createInstances(breve.Stationary, 1)\
		.register(breve.createInstances(breve.Cube, 1)\
		.initWith(breve.vector(WORLD_SIZE, 0.200000, WORLD_SIZE)), breve.vector(0, 0, 0))
		self.surface.setColor(breve.vector(0.7, 0.7, 1.0))
		self.setIntegrationStep(0.2)
		self.enableLighting()
		self.moveLight(breve.vector(0, 10, 0))
		self.disableShadows()
		self.pointCamera(breve.vector(0, 0, 0), breve.vector(0, 60, 60))
		
		self.graphSteps = 0
		self.preyCount = 0
		self.predatorCount = 0
		
		#set predator, prey, food shape
		#self.preyShape = breve.createInstances(breve.Sphere, 1).initWith(1)
		self.preyShape = breve.createInstances(breve.Sphere, 1)
		self.foodShape = breve.createInstances(breve.Cube, 1).initWith(breve.vector(1, 0.600000, 1))
		#self.predatorShape = breve.createInstances(breve.Cube, 1).initWith(breve.vector(1.5, 3, 1.5))
		self.predatorShape = breve.createInstances(breve.Cube, 1)
		self.energySphereShape = breve.createInstances(breve.Sphere, 1).initWith(3.0)
		
		breve.createInstances(breve.Food, FOOD_INIT_COUNT)
		breve.createInstances(breve.Prey, PREY_INIT_COUNT)
		breve.createInstances(breve.Predator, PREDATOR_INIT_COUNT)
		
		prey_count = 'prey_count.txt'
		predator_count = 'predator_count.txt'
		
		self.gnuplotFile = open('gnuplot.txt', 'w')
		self.gnuplotFile.write('set terminal png\n')
		self.gnuplotFile.write('set output "creatures_count.png"\n')
		self.gnuplotFile.write('plot [0:'+str(GRAPH_STEPS_COUNT)+'][0:'+str(MAX_PREY_COUNT+5)+'] "'+prey_count+'" with lines, "'+predator_count+'" with lines\n')
		
		self.predatorFiles = {}
		self.preyFiles = {}
		for f in range(0, FITNESS_SIZE):
			self.predatorFiles[f] = []
			self.preyFiles[f] = []
			self.gnuplotFile.write('set output "predatorFitness_'+str(f)+'.png"\n')
			w = 'plot [0:'+str(GRAPH_STEPS_COUNT)+'][0:'+str(MAX_PREY_COUNT+5)+'] '
			for p in range(0, PARTS):
				filename = 'predatorFitness_'+str(f)+'_'+str(p)+'.txt'
				w += '"'+filename+'" with lines, '
				self.predatorFiles[f].append(open(filename, 'w'))
			self.gnuplotFile.write(w[:-2]+'\n')
			self.gnuplotFile.write('set output "preyFitness_'+str(f)+'.png"\n')
			w = 'plot [0:'+str(GRAPH_STEPS_COUNT)+'][0:'+str(MAX_PREY_COUNT+5)+'] '
			for p in range(0, PARTS):
				filename = 'preyFitness_'+str(f)+'_'+str(p)+'.txt'
				w += '"'+filename+'" with lines, '
				self.preyFiles[f].append(open(filename, 'w'))
			self.gnuplotFile.write(w[:-2]+'\n')
		
		self.gnuplotFile.close()
		
		self.preyCountFile = open(prey_count, 'w')
		self.predatorCountFile = open(predator_count, 'w')

		self.schedule('drawGraphs', (self.controller.getTime() + GRAPH_TIME_STEP))
		
	def drawGraphs(self):
		self.graphSteps += 1
		if(self.graphSteps > GRAPH_STEPS_COUNT):
			self.preyCountFile.close()
			self.predatorCountFile.close()
			for f in range(0, FITNESS_SIZE):
				for p in range(0, PARTS):
					self.predatorFiles[f][p].close()
					self.preyFiles[f][p].close()
			return
		self.preyCountFile.write(str(self.graphSteps)+' '+str(self.preyCount)+'\n')
		self.preyCountFile.flush()
		self.predatorCountFile.write(str(self.graphSteps)+' '+str(self.predatorCount)+'\n')
		self.predatorCountFile.flush()
		
		for f in range(0, FITNESS_SIZE):
			countPredator = []
			countPrey = []
			for p in range(0, PARTS):
				countPredator.append(0)
				countPrey.append(0)
			for item in breve.allInstances("Predator"):
				#print 'item.fitness = '+str(int(item.fitness[f]/((100+PARTS)/PARTS)))+' ; '+str(int(item.fitness[f]))
				countPredator[int(item.fitness[f]/((100+PARTS)/PARTS))] += 1
			for item in breve.allInstances("Prey"):
				#print 'item.fitness = '+str(int(item.fitness[f]/((100+PARTS)/PARTS)))+' ; '+str(int(item.fitness[f]))
				countPrey[int(item.fitness[f]/((100+PARTS)/PARTS))] += 1
			for p in range(0, PARTS):
				self.predatorFiles[f][p].write(str(self.graphSteps)+' '+str(countPredator[p])+'\n')
				self.predatorFiles[f][p].flush()
				self.preyFiles[f][p].write(str(self.graphSteps)+' '+str(countPrey[p])+'\n')
				self.preyFiles[f][p].flush()
		
		self.schedule('drawGraphs', (self.controller.getTime() + GRAPH_TIME_STEP))
			
	def getPreyShape(self):
		return self.preyShape
		
	def getFoodShape(self):
		return self.foodShape
		
	def getPredatorShape(self):
		return self.predatorShape
		
	def getEnergySphereShape(self):
		return self.energySphereShape
		
	def getVelocityFromTo(self, source, target, creature):
		xDist = target.x - source.x 
		zDist = target.z - source.z
		distance = math.sqrt(xDist*xDist+zDist*zDist)
		vel = creature.getVelocity()
		length = math.sqrt(vel.x*vel.x+vel.z*vel.z)
		if(length == 0.0 and creature.previousVelocity):
			vel = creature.previousVelocity
			length = math.sqrt(vel.x*vel.x+vel.z*vel.z)
		else:
			vel = self.controller.randomizeVelocity(creature)
			length = math.sqrt(vel.x*vel.x+vel.z*vel.z)
		if distance != 0.0:
			return length*breve.vector(xDist/distance, 0.0, zDist/distance)
		#else:
		#	return breve.vector(0.0, 0.0, 0.0)
	
	def getPredatorSize(self, predatorFitness):
		return breve.vector(1.0+predatorFitness[0]/50, 1.5+predatorFitness[0]/25, 1.0+predatorFitness[0]/50)
			
	def getPreySize(self, preyFitness):
		return 0.75+preyFitness[0]/200.0
	
	def iterate(self):
		breve.Control.iterate(self)	
		
	def randomizeLocation(self):
		return (breve.randomExpression(breve.vector(WORLD_SIZE-1, 0, WORLD_SIZE-1))\
		- breve.vector(WORLD_SIZE/2.0, -0.2, WORLD_SIZE/2.0))
		
	def randomizeVelocity(self, creature):
		vel = breve.vector()
		vel.y = 0.0
		vel.x = -1.0 + breve.randomExpression(2.0)
		if(breve.randomExpression(100)%2 == 0):
			vel.z = math.sqrt(1.0 - vel.x*vel.x)
		else:
			vel.z = - math.sqrt(1.0 - vel.x*vel.x)
		vel = (MIN_SPEED+MAX_SPEED) * vel/2.0
		#print 'velocity(', creature.fitness[FITNESS_VELOCITY_INCREASE_SPEED_INDEX], ') = ', vel, ' ; ', math.sqrt(vel.x*vel.x+vel.z*vel.z)
		return vel
		#return (breve.randomExpression(breve.vector(0.3, 0.0, 0.3))+breve.vector(0.1, 0.0, 0.1))
	
breve.MyControl = MyControl


###################################################
##################### CREATURE ####################
###################################################
class Creature(breve.Mobile):
	def __init__(self):
		breve.Mobile.__init__(self)
		self.atEdge = 0
		self.hungerLevel = breve.randomExpression(50)
		self.senseDistance = self.hungerLevel/HUNGER_LEVEL_SENSE_PART
		self.age = breve.randomExpression(30)
		self.size = 0
		self.prey = None
		#self.fitness = breve.randomExpression(MAX_FITNESS)
		self.fitness = [0, 0, 0, 0, 0, 0]
		mean = 0
		for i in range(1, FITNESS_SIZE):
			self.fitness[i] = breve.randomExpression(MAX_FITNESS)
			mean += self.fitness[i]
		self.fitness[0] = mean/(FITNESS_SIZE-1)
		#print 'fitness: ', self.fitness
		#print self.age
		self.reproducting = 0
		self.reproduction = 0
		self.schedule('burningFood', ((self.controller.getTime()) + 5.0))
		self.schedule('ageing', ((self.controller.getTime()) + 5.0))
		
	def iterate(self):
		myLoc = self.getLocation()
		myVel = self.getVelocity()
		if ((myLoc.x > WORLD_SIZE/2.0) and (myVel.x > 0.0)):
			self.atEdge = 1
			myVel.x = -myVel.x
		else:
			if((myLoc.z > WORLD_SIZE/2.0) and (myVel.z > 0.0)):
				self.atEdge = 1
				myVel.z = -myVel.z
			else:
				if ((myLoc.x < -WORLD_SIZE/2.0) and (myVel.x < 0.0)):
					self.atEdge = 1
					myVel.x = -myVel.x
				else:
					if ((myLoc.z < -WORLD_SIZE/2.0) and (myVel.z < 0.0)):
						self.atEdge = 1
						myVel.z = -myVel.z
					else:
						self.atEdge = 0
		if self.atEdge:
			self.setVelocity(myVel)
		
		breve.Mobile.iterate(self)
		
	def burningFood(self):
		if self.hungerLevel >= 100:
			#breve.deleteInstance(self)
			self.destroyMe()
			#print 'creature deleted - hunger'
			return
		self.hungerLevel += FOOD_BURNING_STEP*(1.0 - self.fitness[FITNESS_FOOD_BURNING_SPEED_INDEX]/100.0)
		self.senseDistance = (1.0 + self.fitness[FITNESS_SENSE_DISTANCE_INDEX]/100.0)*self.hungerLevel/HUNGER_LEVEL_SENSE_PART
		self.schedule('burningFood', ((self.controller.getTime()) + 5.0))
		
	def ageing(self):
		if self.age >= 100:
			self.destroyMe()
			#breve.deleteInstance(self)
			#print 'creature deleted - age'
			return
		self.age += AGE_STEP
		if not self.reproducting:
			self.setColor(self.getColor()-breve.vector(0.02, 0, 0))
		v = self.getVelocity()
		v_len = math.sqrt(v.x*v.x+v.z*v.z)
		if(v_len < MIN_SPEED or v_len > MAX_SPEED):
			return
		if self.age < AGE_SPEED_LEVEL:
			vel = (1.0 + self.fitness[FITNESS_VELOCITY_INCREASE_SPEED_INDEX]/1200.0)*self.getVelocity()
			self.setVelocity(vel)
		else:
			self.setVelocity((1.0 - self.fitness[FITNESS_VELOCITY_INCREASE_SPEED_INDEX]/1200.0)*self.getVelocity())
		self.schedule('ageing', ((self.controller.getTime()) + 5.0))	
		
	def calculateFitness(self, parent1, parent2):
		self.fitness[0] = 0
		for i in range(1, FITNESS_SIZE):
			rand = breve.randomExpression(MAX_FITNESS)
			self.fitness[i] = parent1.fitness[i]*rand/100.0+parent1.fitness[i]*(MAX_FITNESS-rand)/100.0
			rand = breve.randomExpression(MAX_FITNESS)
			if(rand % 10 == 0):
				self.fitness[i] = (self.fitness[i]*2) % MAX_FITNESS
			self.fitness[0] += self.fitness[i]
		self.fitness[0] /= FITNESS_SIZE-1
	
breve.Creature = Creature


###################################################
####################### PREY ######################
###################################################
class Prey(breve.Creature):
	def __init__(self):
		breve.Creature.__init__(self)
		self.size = self.controller.getPreySize(self.fitness)
		#print 'prey size: ', self.size
		self.setShape(self.controller.getPreyShape().initWith(self.size))
		self.setColor(breve.vector(0.5+self.age/200.0, 0, 0))
		self.eating = None
		self.attacker = None
		self.closestPredator = None
		self.foodTarget = None
		self.prey = 1
		self.energyLevel = 50+breve.randomExpression(50)
		self.previousVelocity = None
		self.predatorDistance = PREY_DISTANCE_SENSE_TO_PREDATOR
		self.move(self.controller.randomizeLocation())
		self.move(self.getLocation()+breve.vector(0.0, 1.0, 0.0))
		self.handleCollisions('Food', 'foodCollide')
		self.handleCollisions('Prey', 'preyCollide')
		self.setVelocity(PREY_SPEED*self.controller.randomizeVelocity(self))
		self.destroyed = 0
		self.speedUp = 1.0+breve.randomExpression(2.0)
		self.energySphere = None
		self.controller.preyCount += 1
		
	def iterate(self):
		if self.energySphere:
			return
		self.closestPredator = self.getClosestPredator()
		if self.closestPredator:
			self.eating = None
			self.setVelocity(PREY_SPEED*(-1)*self.controller.getVelocityFromTo(self.getLocation(), self.closestPredator.getLocation(), self))
			#print 'self.getVelocity()', self.getLocation(), self.closestPredator.getLocation(), self.closestPredator.getLocation(), self.getVelocity()
			myLoc = self.getLocation()
			myVel = self.getVelocity()
			predatorLoc = self.closestPredator.getLocation()
			if ((myLoc.x > WORLD_SIZE/2.0) and (myVel.x > 0.0)):
				self.atEdge = 1
				myVel.x = 0
				if predatorLoc.z > myLoc.z:
					myVel.z = -1
				else:
					myVel.z = 1
			else:
				if((myLoc.z > WORLD_SIZE/2.0) and (myVel.z > 0.0)):
					self.atEdge = 1
					myVel.z = 0
					if predatorLoc.x > myLoc.x:
						myVel.x = -1
					else:
						myVel.x = 1
				else:
					if ((myLoc.x < -WORLD_SIZE/2.0) and (myVel.x < 0.0)):
						self.atEdge = 1
						myVel.x = 0
						if predatorLoc.z > myLoc.z:
							myVel.z = -1
						else:
							myVel.z = 1
					else:
						if ((myLoc.z < -WORLD_SIZE/2.0) and (myVel.z < 0.0)):
							self.atEdge = 1
							myVel.z = 0
							if predatorLoc.x > myLoc.x:
								myVel.x = -1
							else:
								myVel.x = 1
						else:
							self.atEdge = 0
			if self.atEdge:
				self.setVelocity(myVel)

		else:
			if self.eating:
				self.eat()
			if self.hungerLevel < HUNGER_LEVEL_TO_ACTIVATE_SENSE and not self.eating and not self.reproducting:
				closestFood = self.getClosestFood()
				if closestFood and self.foodTarget != closestFood:
					self.foodTarget = closestFood
					foodLocation = closestFood.getLocation()
					myLocation = self.getLocation()
					self.setVelocity(PREY_SPEED*self.controller.getVelocityFromTo(myLocation, foodLocation, self))
		breve.Creature.iterate(self)
	
	def foodCollide(self, food):
		if self.eating or self.hungerLevel == 0:
			return
		else:
			self.startEating()
			self.eating = food
			
	def eat(self):
		if self.hungerLevel == 0:
			self.afterEating()
			self.eating = None
			return
			
		if self.hungerLevel > (1.0 + self.fitness[FITNESS_FOOD_EATING_SPEED_INDEX]/100.0)*HUNGER_LEVEL_STEP:
			self.hungerLevel -= self.eating.getFood((1.0 + self.fitness[FITNESS_FOOD_EATING_SPEED_INDEX]/100.0)*HUNGER_LEVEL_STEP)
		else:
			self.hungerLevel -= self.eating.getFood(self.hungerLevel)
			
		if self.eating.hasNoFood():
			self.eating.destroyMe()
				
		if self.eating.hasNoFood() or self.hungerLevel == 0:
			self.afterEating()
			self.eating = None
		
	def startEating(self):
		#print 'stop'
		self.previousVelocity = self.getVelocity()
		self.setVelocity(breve.vector(0, 0, 0))
		
	def afterEating(self):
		#print 'START'
		if not self.energySphere:
			self.setVelocity(self.previousVelocity)
		
	def preyCollide(self, prey):
		if not self.closestPredator and self.hungerLevel <= MIN_FOOD_LEVEL_FOR_REPRODUCTION and self.age >= MIN_AGE_FOR_REPRODUCTION and self.age <= MAX_AGE_FOR_REPRODUCTION and self.reproduction < MAX_PREY_REPRODUCTION and not self.reproducting and not prey.reproducting and not self.eating and not prey.eating and not self.energySphere and not prey.energySphere:
			self.reproduct(prey)
	
	def getClosestFood(self):
		bestDistance = self.senseDistance
		best = None
		for item in breve.allInstances("Food"):
			if (breve.length((self.getLocation() - item.getLocation())) < bestDistance):
				best = item
				bestDistance = breve.length((self.getLocation() - item.getLocation()))
		return best
		
	def getClosestPredator(self):
		bestDistance = self.predatorDistance
		best = None
		for item in breve.allInstances("Predator"):
			if (breve.length((self.getLocation() - item.getLocation())) < bestDistance):
				best = item
				bestDistance = breve.length((self.getLocation() - item.getLocation()))
		return best
		
	def createNewPrey(self):
		#print 'createNewPrey'
		newPrey = breve.createInstances(breve.Prey, 1)
		newPrey.reproducting = 1
		newPrey.hungerLevel = 0
		rand = breve.randomExpression(MAX_FITNESS)
		newPrey.calculateFitness(self, self.partner)
		newPrey.age = 0
		newPrey.setVelocity(breve.vector(0, 0, 0))
		newPrey.move(self.getLocation()+breve.vector(1.0, 0.0, 1.0))
		newPrey.previousColor = newPrey.getColor()
		newPrey.setColor(breve.vector(1.0, 1.0, 0.0))
		self.newPrey = newPrey
		self.schedule('afterBorn', ((self.controller.getTime()) + REPRODUCTION_TIME/2.0))
		
	def afterBorn(self):
		#print 'afterBorn'
		self.newPrey.reproducting = 0
		self.setColor(self.previousColor)
		self.partner.setColor(self.partner.previousColor)
		self.newPrey.setColor(self.newPrey.previousColor)
		if not self.newPrey.energySphere:
			self.newPrey.setVelocity(PREY_SPEED*self.controller.randomizeVelocity(self.newPrey))
		if not self.energySphere:
			self.setVelocity(self.previousVelocity)
		if not self.partner.energySphere:
			self.partner.setVelocity(self.partner.previousVelocity)
		self.schedule('afterReproduct', ((self.controller.getTime()) + PAUSE_AFTER_REPRODUCTION))
		
	def afterReproduct(self):
		#print 'afterReproduct'
		self.reproducting = 0
		self.partner.reproducting = 0
	
	def reproduct(self, partner):
		#print 'stop'
		self.reproduction += 1
		partner.reproduction += 1
		self.reproducting = 1
		partner.reproducting = 1
		self.previousVelocity = self.getVelocity()
		self.setVelocity(breve.vector(0, 0, 0))
		partner.previousVelocity = partner.getVelocity()
		partner.setVelocity(breve.vector(0, 0, 0))
		self.previousColor = self.getColor()
		partner.previousColor = partner.getColor()
		self.setColor(breve.vector(0.0, 0.0, 1.0))
		partner.setColor(breve.vector(0.0, 0.0, 1.0))
		self.partner = partner
		self.schedule('createNewPrey', ((self.controller.getTime()) + REPRODUCTION_TIME/2.0))
		
	def showEnergySphere(self):
		if not self.energySphere:
			#print 'showEnergySphere'
			self.setVelocity(breve.vector(0, 0, 0))
			self.energySphere = breve.createInstances(breve.EnergySphere, 1)
			self.energySphere.move(self.getLocation())
			self.energySphere.setVelocity(breve.vector(0, 0, 0))
			
	def removeEnergySphere(self):
		#print 'removeEnergySphere'
		if self.energySphere:
			breve.deleteInstance(self.energySphere)
			self.energySphere = None
			
	def getEnergy(self, energyAmount):
		#print 'energyLevel = '+ str(self.energyLevel)
		if self.energyLevel < energyAmount:
			self.energyLevel = 0
			return self.energyLevel
		else:
			self.energyLevel -= energyAmount
			return energyAmount
			
	def hasNoEnergy(self):
		if self.energyLevel == 0:
			return 1
		else:
			return 0
		
	def destroyMe(self):
		#print 'preyDestroy'
		if not self.destroyed:
			breve.deleteInstance(self)
			self.destroyed = 1
			self.removeEnergySphere()
			self.controller.preyCount -= 1
	
breve.Prey = Prey


###################################################
################### PREDATOR ######################
###################################################
class Predator(breve.Creature):
	def __init__(self):
		breve.Creature.__init__(self)
		self.size = self.controller.getPredatorSize(self.fitness)
		self.setShape(self.controller.getPredatorShape().initWith(self.size))
		self.setColor(breve.vector(1, 1, 0.5+self.age/200.0))
		self.eating = None
		self.attacking = None
		self.preyTarget = None
		self.previousVelocity = None
		self.reproduction = 0
		self.destroyed = 0
		self.sensePreyDistance = PREDATOR_DISTANCE_SENSE_TO_PREY
		self.attacking = None
		self.move(self.controller.randomizeLocation())
		self.move(self.getLocation()+breve.vector(0.0, 1.0, 0.0))
		self.handleCollisions('Predator', 'predatorCollide')
		self.handleCollisions('Prey', 'preyCollide')
		self.setVelocity(PREDATOR_SPEED*self.controller.randomizeVelocity(self))
		self.controller.predatorCount += 1
		
	def iterate(self):
		closestPrey = self.getClosestPrey()
		if self.hungerLevel >= PREDATOR_HUNGER_LEVEL_TO_ACTIVATE_SENSE and not self.attacking and closestPrey:
			self.preyTarget = closestPrey
			preyLocation = closestPrey.getLocation()
			myLocation = self.getLocation()
			xDist = preyLocation.x - myLocation.x
			zDist = preyLocation.z - myLocation.z
			distance = math.sqrt((xDist*xDist+zDist*zDist))
			if distance != 0:
				self.setVelocity(breve.vector(xDist/distance, 0.0, zDist/distance))
			#else:
			#	self.setVelocity(self.controller.randomizeVelocity())
		else:
			self.preyTarget = None
		if self.attacking:
			#self.setVelocity(self.attacking.getVelocity())
			self.attack()
		breve.Creature.iterate(self)
	
	def attack(self):
		if self.hungerLevel == 0:
			self.afterAttacking()
			self.attacking = None
			return
		if self.hungerLevel > ENERGY_LEVEL_STEP:
			self.hungerLevel -= self.attacking.getEnergy(ENERGY_LEVEL_STEP)
		else:
			self.hungerLevel -= self.attacking.getEnergy(self.hungerLevel)
		if self.attacking.hasNoEnergy():
			self.attacking.destroyMe()
				
		if self.attacking.hasNoEnergy() or self.hungerLevel == 0:
			self.afterAttacking()
			self.attacking = None
			
	def startAttacking(self):
		self.previousVelocity = self.getVelocity()
		self.setVelocity(breve.vector(0, 0, 0))
		self.attacking.showEnergySphere()
		
	def afterAttacking(self):
		self.setVelocity(self.previousVelocity)
		#self.setVelocity(self.controller.randomizeVelocity())
		#self.attacking.removeEnergySphere()
			
	def preyCollide(self, prey):
		if self.attacking or self.hungerLevel < PREDATOR_HUNGER_LEVEL_TO_ACTIVATE_SENSE:
			return
		else:
			print 'preyCollide'
			self.attacking = prey
			self.startAttacking()

	def readyForReproducting(self):
		return (not self.preyTarget and self.hungerLevel <= MIN_FOOD_LEVEL_FOR_REPRODUCTION and self.age >= MIN_AGE_FOR_REPRODUCTION and self.age <= MAX_AGE_FOR_REPRODUCTION and self.reproduction < MAX_PREDATOR_REPRODUCTION and not self.reproducting and not self.attacking)
	
	def predatorCollide(self, predator):
		#print 'predatorCollide'
		if(self.readyForReproducting() and predator.readyForReproducting()):
			self.reproduct(predator)
			
	def createNewPredator(self):
		#print 'createNewPredator'
		newPredator = breve.createInstances(breve.Predator, 1)
		newPredator.reproducting = 1
		newPredator.hungerLevel = 0
		rand = breve.randomExpression(101)
		newPredator.calculateFitness(self, self.partner.fitness)
		newPredator.age = 0
		newPredator.setVelocity(breve.vector(0, 0, 0))
		newPredator.move(self.getLocation()+breve.vector(1.0, 0.0, 1.0))
		newPredator.previousColor = newPredator.getColor()
		newPredator.setColor(breve.vector(1.0, 1.0, 0.0))
		self.newPredator = newPredator
		self.schedule('afterBorn', ((self.controller.getTime()) + REPRODUCTION_TIME/2.0))
		
	def afterBorn(self):
		#print 'afterBorn'
		self.newPredator.reproducting = 0
		self.setColor(self.previousColor)
		self.partner.setColor(self.partner.previousColor)
		self.newPredator.setColor(self.newPredator.previousColor)
		self.setVelocity(self.previousVelocity)
		self.partner.setVelocity(self.partner.previousVelocity)
		self.newPredator.setVelocity(PREDATOR_SPEED*self.controller.randomizeVelocity(self))
		self.schedule('afterReproduct', ((self.controller.getTime()) + PAUSE_AFTER_REPRODUCTION))
		
	def afterReproduct(self):
		#print 'afterReproduct'
		self.reproducting = 0
		self.partner.reproducting = 0
	
	def reproduct(self, partner):
		#print 'stop'
		self.reproduction += 1
		partner.reproduction += 1
		self.reproducting = 1
		partner.reproducting = 1
		self.previousVelocity = self.getVelocity()
		self.setVelocity(breve.vector(0, 0, 0))
		partner.previousVelocity = partner.getVelocity()
		partner.setVelocity(breve.vector(0, 0, 0))
		self.previousColor = self.getColor()
		partner.previousColor = partner.getColor()
		self.setColor(breve.vector(0.0, 0.0, 1.0))
		partner.setColor(breve.vector(0.0, 0.0, 1.0))
		self.partner = partner
		self.schedule('createNewPredator', ((self.controller.getTime()) + REPRODUCTION_TIME/2.0))
	
	def getClosestPrey(self):
		bestDistance = self.sensePreyDistance
		best = None
		for item in breve.allInstances("Prey"):
			if (breve.length((self.getLocation() - item.getLocation())) < bestDistance):
				best = item
				bestDistance = breve.length((self.getLocation() - item.getLocation()))
		return best

	def destroyMe(self):
		if not self.destroyed:
			breve.deleteInstance(self)
			self.destroyed = 1
			self.controller.predatorCount -= 1
			#if self.attacking:
			#	self.attacking.removeEnergySphere()	
		
breve.Predator = Predator


###################################################
####################### FOOD ######################
###################################################
class Food(breve.Stationary):
	def __init__(self):
		breve.Stationary.__init__(self)
		self.setColor(breve.vector(0, 1, 0))
		self.foodLevel = 10
		self.destroyed = 0
		self.setShape(self.controller.getFoodShape())
		self.move(self.controller.randomizeLocation())
		
	def getFood(self, foodAmount):
		if self.foodLevel < foodAmount:
			self.foodLevel = 0
			return self.foodLevel
		else:
			self.foodLevel -= foodAmount
			return foodAmount
			
	def hasNoFood(self):
		if self.foodLevel == 0:
			return 1
		else:
			return 0
			
	def destroyMe(self):
		if not self.destroyed:
			breve.deleteInstance(self)
			breve.createInstances(breve.Food, 1)
			self.destroyed = 1
		
breve.Food = Food

class EnergySphere(breve.Mobile):
	def __init__(self):
		breve.Mobile.__init__(self)
		self.setShape(self.controller.getEnergySphereShape())
		self.setTransparency(0.2)
		self.setColor( breve.vector(0, 0, 0))

	def iterate(self):
		breve.Mobile.iterate(self)

	def kill(self):
		breve.deleteInstances(self)


breve.EnergySphere = EnergySphere

# Create an instance of our controller object to initialize the simulation
control = MyControl()